package com.google.code.openperfmon.service;

import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;

import org.apache.log4j.Logger;

import com.google.code.openperfmon.Status;
import com.google.code.openperfmon.domain.MonitorDefinition;

public class ExecutionService {
	private static Logger logger = Logger.getLogger(ExecutionService.class);
	
	public void execute(final String script, final ExecutionContext ctx) {
		StringBuilder wholeScript = new StringBuilder();
		if (ctx.getInputs() != null) for (String inp : ctx.getInputs()) {
			wholeScript.append(inp);
			wholeScript.append("\n");
		}
		wholeScript.append("importClass(").append(Status.class.getName()).append(");\n");
		wholeScript.append(script);
		
		ctx.setStatus(Status.Black);
		ScriptEngine engine = getScriptEngine();
		try {
			Bindings bind = engine.createBindings();
			bind.put("ctx", ctx);
			engine.eval(wholeScript.toString(), bind);
			ctx.setSuccess(true);
		}
		catch (Exception e) {
			logger.error(e);
			ctx.setSuccess(false);
			String msg = e.getMessage();
			if (msg != null && msg.startsWith("sun.org.mozilla.javascript.internal.EcmaError:")) msg = msg.substring(47);
			ctx.setMessage("Error executing script. " + msg);
		}
	}
	
	public ExecutionContext test(MonitorDefinition def, String testHost) {
		ExecutionContext ctx = new ExecutionContext();
		ctx.addInput(def.getInputVariables());
		ctx.addInput("host = '" + testHost + "';");
		execute(def.getBody(), ctx);
		return ctx;
	}
	
	ScriptEngine getScriptEngine() {
		if (singleton != null) return singleton;
		
		ScriptEngineManager m = new ScriptEngineManager();
		ScriptEngine engine = m.getEngineByName("js");
		
		
		if (supportsMutithreading == null) {
			ScriptEngineFactory fact = engine.getFactory();
			supportsMutithreading = "MULTITHREADED".equals(fact.getParameter("THREADING"));
		}
		
		if (supportsMutithreading.booleanValue()) {
			singleton = engine;
			return singleton;
		}
		return engine;
	}
	
	private ScriptEngine singleton = null;
	private Boolean supportsMutithreading = null;
}
